import React, { Component } from 'react'
import { Graph, Path, ToolsView } from '@antv/x6'
import '@antv/x6-react-shape'
import ReactDOM from 'react-dom'
import { Dropdown } from 'antd'
import { connect } from '@umijs/max'
import styles from './index.less'
import { getHashParameterByName } from '@/utils/helper'

const icon = {
  12: <span className={`${styles.offline_icon} ${styles.offline_icon_z}`}><i className="iconfont icon-xunijiedian" /></span>,
  13: <span className={`${styles.offline_icon} ${styles.offline_icon_green}`}><i className="iconfont icon-HiveSQL" /></span>,
  14: <span className={`${styles.offline_icon} ${styles.offline_icon_green}`}><i className="iconfont icon-MapRduce" /></span>,
  15: <span className={`${styles.offline_icon} ${styles.offline_icon_green}`}><i className="iconfont icon-Impala" /></span>,
  16: <span className={`${styles.offline_icon} ${styles.offline_icon_green}`}><i className="iconfont icon-Shell" /></span>,
  17: <span className={`${styles.offline_icon} ${styles.offline_icon_green}`}><i className="iconfont icon-Python2" /></span>,
  18: <span className={`${styles.offline_icon} ${styles.offline_icon_green}`}><i className="iconfont icon-Python3" /></span>,
  19: <span className={`${styles.offline_icon} ${styles.offline_icon_green}`}><i className="iconfont icon-Pyspark" /></span>,
  20: <span className={`${styles.offline_icon} ${styles.offline_icon_red}`}><i className="iconfont icon-lixiantongbu" /></span>,
  21: <span className={`${styles.offline_icon} ${styles.offline_icon_red}`}><i className="iconfont icon-jiekoucaiji" /></span>,
  22: <span className={`${styles.offline_icon} ${styles.offline_icon_blue}`}><i className="iconfont icon-shujuzhiliang1" /></span>,
}

const color = {
  12: 'node_z',
  13: 'node_green',
  14: 'node_green',
  15: 'node_green',
  16: 'node_green',
  17: 'node_green',
  18: 'node_green',
  19: 'node_green',
  20: 'node_red',
  21: 'node_red',
  22: 'node_blue',
}

const image = {
  3: <svg t="1650424548437" className="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="77657" width="20" height="20"><path d="M512 64a448 448 0 1 0 448 448A448 448 0 0 0 512 64z m0 810.666667a362.666667 362.666667 0 1 1 362.666667-362.666667 362.666667 362.666667 0 0 1-362.666667 362.666667z" p-id="77658" fill="#7fe312" /><path d="M725.333333 343.68L466.346667 602.666667 298.666667 434.986667l-60.373334 60.373333 167.68 167.68 60.373334 60.373333 60.373333-60.373333 258.986667-259.2L725.333333 343.68z" p-id="77659" fill="#7fe312" /></svg>,
  4: <svg t="1650424588552" className="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="77849" width="20" height="20"><path d="M724.266667 300.8l-150.826667 150.826667-150.826667-150.826667-60.373333 60.373333L513.066667 512l-150.826667 150.826667 60.373333 60.373333 150.826667-150.826667 150.826667 150.826667 60.373333-60.373333L633.813333 512l150.826667-150.826667-60.373333-60.373333z" p-id="77850" fill="#e01236" /><path d="M573.44 64a448 448 0 1 0 448 448 448 448 0 0 0-448-448z m0 810.666667a362.666667 362.666667 0 1 1 362.666667-362.666667 362.666667 362.666667 0 0 1-362.666667 362.666667z" p-id="77851" fill="#e01236" /></svg>,
  2: <svg t="1650424609124" className="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="78041" width="20" height="20"><path d="M945.706667 189.226667l-61.44 46.933333A462.506667 462.506667 0 0 0 522.666667 64 453.333333 453.333333 0 0 0 64 512a453.333333 453.333333 0 0 0 458.666667 448 458.666667 458.666667 0 0 0 431.146666-294.4 8.533333 8.533333 0 0 0-5.333333-11.093333l-61.866667-21.333334A8.746667 8.746667 0 0 0 874.666667 640c-1.92 5.333333-4.053333 10.666667-6.4 15.786667a365.653333 365.653333 0 0 1-78.933334 115.626666 375.68 375.68 0 0 1-119.253333 78.72 385.706667 385.706667 0 0 1-292.48 0 372.48 372.48 0 0 1-199.893333-195.413333 361.173333 361.173333 0 0 1 0-285.653333 368.64 368.64 0 0 1 80.426666-116.693334 379.093333 379.093333 0 0 1 119.466667-78.72 385.706667 385.706667 0 0 1 292.48 0 380.373333 380.373333 0 0 1 149.333333 112.213334l-65.706666 50.133333a8.533333 8.533333 0 0 0 3.2 15.146667l192 45.866666a8.746667 8.746667 0 0 0 10.88-8.32v-192a8.96 8.96 0 0 0-14.293334-6.613333z" p-id="78042" fill="#888585" /></svg>,
}

// 右击菜单
class ContextMenuTool extends ToolsView.ToolItem {
  render() {
    super.render()
    if (this.options.onHide) {
      this.options.onHide.call(this)
    }
    this.knob = ToolsView.createElement('div', false)
    this.knob.style.position = 'absolute'
    this.container.appendChild(this.knob)
    this.updatePosition(this.options)
    setTimeout(() => {
      this.toggleTooltip(true)
    })
    return this
  }

  toggleTooltip(visible) {
    ReactDOM.unmountComponentAtNode(this.knob)
    document.removeEventListener('mousedown', this.onMouseDown)

    if (visible) {
      ReactDOM.render(
        <Dropdown
          visible
          trigger={['contextMenu']}
          overlay={this.options.menu}
        >
          <a />
        </Dropdown>,
        this.knob,
      )
      document.addEventListener('mousedown', this.onMouseDown)
    }
  }

  updatePosition(pos) {
    const style = this.knob.style
    if (pos) {
      style.left = `${pos.x}px`
      style.top = `${pos.y}px`
    } else {
      style.left = '-1000px'
      style.top = '-1000px'
    }
  }

  onMouseDown = (e) => {
    setTimeout(() => {
      this.updatePosition()
      this.toggleTooltip(false)
      if (this.options.onHide) {
        this.options.onHide.call(this)
      }
    }, 200)
  };
}

ContextMenuTool.config({
  tagName: 'div',
  isSVGElement: false,
})

// 连线右击弹框
Graph.registerEdgeTool('contextmenu', ContextMenuTool, true)
// 节点右击弹框
Graph.registerNodeTool('contextmenu', ContextMenuTool, true)

// 节点样式
class AlgoNode1 extends React.Component {
  shouldComponentUpdate() {
    const { node } = this.props
    if (node) {
      if (node.hasChanged('data')) {
        return true
      }
    }
    return false
  }

  render() {
    const { node } = this.props
    const data = node?.getData()
    const { label, status = '' } = data
    return (
      <div className={`node ${styles.node} ${styles[color[data.nodeType]]} ${color[data.nodeType]}`}>
        {icon[data.nodeType]}
        <span className={`${styles.label} ${styles.text_overflow_single}`} title={label}>{label}</span>
        <span className={`${styles.status} ${styles[status]}`}>
          {status === 3 && image[status]}
          {status === 4 && image[status]}
          {status === 2 && image[status]}
        </span>
      </div>
    )
  }
}

@connect(({ operationDetail }) => ({ ...operationDetail }))
class WorkFlow extends Component {
  componentWillMount() {
    // 节点、锚点
    Graph.registerNode(
      'node',
      {
        inherit: 'react-shape',
        width: 220,
        height: 42,
        component: <AlgoNode1 />,
        ports: {
          groups: {
            in: {
              position: 'top',
              attrs: {
                circle: {
                  r: 4,
                  magnet: true,
                  stroke: '#C2C8D5',
                  strokeWidth: 1,
                  fill: '#fff',
                },
              },
            },
            out: {
              position: 'bottom',
              attrs: {
                circle: {
                  r: 4,
                  magnet: true,
                  stroke: '#C2C8D5',
                  strokeWidth: 1,
                  fill: '#fff',
                },
              },
            },
          },
        },
      },
      true,
    )

    // 线
    Graph.registerEdge(
      'edge',
      {
        inherit: 'edge',
        attrs: {
          line: {
            stroke: '#C2C8D5',
            strokeWidth: 1,
            targetMarker: {
              args: {
                size: 8,
              },
              name: 'classic',
            }, // 箭头
          },
        },
      },
      true,
    )

    Graph.registerConnector(
      'algo-connector-workflow',
      (s, e) => {
        const offset = 4
        const deltaY = Math.abs(e.y - s.y)
        const control = Math.floor((deltaY / 3) * 2)

        const v1 = { x: s.x, y: s.y + offset + control }
        const v2 = { x: e.x, y: e.y - offset - control }

        return Path.normalize(
          `M ${s.x} ${s.y}
       L ${s.x} ${s.y + offset}
       C ${v1.x} ${v1.y} ${v2.x} ${v2.y} ${e.x} ${e.y - offset}
       L ${e.x} ${e.y}
      `,
        )
      },
      true,
    )
  }

  componentDidMount() {
    this.init()
    this.fetchData()
  }

  componentWillUnmount() {
    this?.graph?.dispose()
  }

  init = () => {
    this.graph = new Graph({
      container: document.getElementById('workFlowContainer'),
      snapline: true, // 对齐线
      panning: {
        enabled: true,
        // eventTypes: ['leftMouseDown', 'mouseWheel'], // 是否加左右上下滚动条
      },
      mousewheel: {
        enabled: true,
        // modifiers: 'ctrl', // 缩放是否ctrl+滚轮
        factor: 1.1,
        // maxScale: 1.5, // 最大缩放
        // minScale: 0.1, // 最小缩放
      },
      grid: {
        size: 15, // 网格大小 10px
        type: 'doubleMesh', // 指定网格类型
        visible: true, // 绘制网格，默认绘制 dot 类型网格
        args: [
          {
            color: '#eee', // 主网格线颜色
            thickness: 1, // 主网格线宽度
          },
          {
            color: '#ddd', // 次网格线颜色
            thickness: 1, // 次网格线宽度
            factor: 4, // 主次网格线间隔
          },
        ],
      },
      highlighting: {
        magnetAdsorbed: {
          name: 'stroke',
          args: {
            attrs: {
              fill: '#fff',
              stroke: '#31d0c6',
              strokeWidth: 1,
            },
          },
        },
      },
      connecting: {
        snap: {
          radius: 20,
        },
        allowBlank: false,
        allowLoop: false,
        allowEdge: false,
        highlight: true,
        allowMulti: 'withPort',
        allowNode: false,
        connector: 'algo-connector-workflow',
        connectionPoint: 'anchor',
        anchor: 'center',
        validateMagnet(e) {
          return e.magnet.getAttribute('port-group') !== 'in'
        },
        validateEdge({ edge, type }) {
          return edge.getTarget().port.indexOf('out') === -1
        },
        createEdge: () => this.graph.createEdge({
          shape: 'edge',
          attrs: {
            line: {
              strokeDasharray: '5 5',
            },
          },
          zIndex: -1,
        }),
      },
      // autoResize: true, //是否自动扩充/缩小画布 移动节点/边时将自动计算需要的画布大小，当超出当前画布大小时，按照 pageWidth 和  pageHeight 自动扩充画布。反之，则自动缩小画布。
      selecting: {
        enabled: true,
        rubberband: false,
        multiple: true,
        strict: true,
        showNodeSelectionBox: false,
        selectNodeOnMoved: false,
      },
    })

    this.graph.on('edge:connected', ({ edge }) => {
      edge.attr({
        line: {
          strokeDasharray: '',
        },
      })
    })

    this.graph.on('node:change:data', ({ node }) => {
      const edges = this.graph.getIncomingEdges(node)
      const { status } = node.getData()
      edges?.forEach((edge) => {
        if (status === 'running') {
          edge.attr('line/strokeDasharray', 5)
          edge.attr('line/style/animation', 'running-line 30s infinite linear')
        } else {
          edge.attr('line/strokeDasharray', '')
          edge.attr('line/style/animation', '')
        }
      })
    })

    // 节点点击事件
    this.graph.on('node:click', ({ node }) => {
      const data = node?.getData() || {}
      const { id } = data
      //
      this.props.dispatch({
        type: 'operationDetail/queryNodeDetail',
        params: {
          // taskType: nodeType,
          nodeId: id,
          taskFlowJobId: getHashParameterByName('jobId'),
        },
        cb: (res) => {
          // console.log('res', res)
        },
      })
    })
  }

  fetchData = () => {
    const { infoData } = this.props
    const data = []
    const nodes = infoData?.nodes || []
    const edges = infoData?.edges || []

    nodes.map((item) => {
      if (item?.nodeType === 12) {
        data.push(
          {
            id: item.nodeId,
            shape: 'node',
            x: Number(item?.coordX),
            y: Number(item?.coordY),
            data: {
              label: item?.nodeName,
              status: '',
              id: item?.nodeId,
              nodeType: item?.nodeType,
            },
            ports: [
              {
                id: `${item?.nodeId}_out`,
                group: 'out',
              },
            ],
          },
        )
      } else {
        data.push(
          {
            id: item.nodeId,
            shape: 'node',
            x: Number(item?.coordX),
            y: Number(item?.coordY),
            data: {
              label: item?.nodeName,
              status: '',
              id: item?.nodeId,
              nodeType: item?.nodeType,
            },
            ports: [
              {
                id: `${item?.nodeId}_in`,
                group: 'in',
              },
              {
                id: `${item?.nodeId}_out`,
                group: 'out',
              },
            ],
          },
        )
      }
    })
    edges.map((item) => {
      data.push(
        {
          // id: `${item.from}_${item.to}`,
          id: `${item?.upNodeId}_${item?.downNodeId}`,
          shape: 'edge',
          source: {
            cell: item?.upNodeId,
            port: `${item?.upNodeId}_out`,
          },
          target: {
            cell: item?.downNodeId,
            port: `${item?.downNodeId}_in`,
          },
          zIndex: 0,
        },
      )
    })
    // this.setState({
    //   data,
    // })

    this.initNode(data)
    // this.showNodeStatus(nodeStatusList)
    this.graph.centerContent()

    // setTimeout(() => {
    //   this.initNode(arr)
    //   this.showNodeStatus(nodeStatusList)
    //   this.graph.centerContent()
    // }, 1000)
  }

  // 初始化节点/边
  initNode = (data) => {
    const cells = []
    data?.forEach((item) => {
      if (item.shape === 'node') {
        cells.push(this.graph.createNode(item))
      } else {
        cells.push(this.graph.createEdge(item))
      }
    })
    this.graph.resetCells(cells)
  }

  // 显示节点状态
  showNodeStatus = (statusList) => {
    const status = statusList?.shift()
    status?.forEach((item) => {
      const { id, status: statusParams } = item || {}
      const node = this.graph.getCellById(id)
      const data = node?.getData()
      node.setData({
        ...data,
        status: statusParams,
      })
    })
    setTimeout(() => { // 对比一下
      this.showNodeStatus(statusList)
    }, 3000)
  }

  render() {
    return (
      <div className={styles.work_flow} id="workFlowContainer" />
    )
  }
}

export default WorkFlow
